package org.hxzon.demo.coyote;

import java.io.IOException;

import org.apache.coyote.Adapter;
import org.apache.coyote.Request;
import org.apache.coyote.Response;
import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.C2BConverter;
import org.apache.tomcat.util.net.SocketStatus;

public class StartHttp11Server {
	/**
	 * Start http on the port. It creates an internal thread pool. This method
	 * doesn't block, all processing will be done in the thread pool.
	 * 
	 * @param port
	 * @throws Exception
	 */
	private static void startHttp(int port) throws Exception {
		// Http11Protocol proto=new Http11Protocol();
		Http11NioProtocol proto = new Http11NioProtocol();
		proto.setPort(port);

		proto.setAdapter(new MyAdapter());

		proto.init();
		proto.start();
		while (true) {

		}
		// System.out.println("stop");
	}

	static class MyAdapter implements Adapter {

		// public void service(Request req, Response res) throws Exception {
		// System.out.println("Incoming request " +
		// req.queryString().toString());
		// res.setStatus(200);
		//
		// // tomcat doesn't use a stream internally - so the object can be
		// recycled and avoids
		// // buffer to buffer copy.
		//
		// // To write to the stream, tomcat uses 'byte chunk' - a buffer
		// optimized for char-byte conversions
		// // This is similar with NIO buffers
		// ByteChunk myChunk=new ByteChunk();
		//
		// // let's just send some bytes - more advanced mechanism later
		// String hello="hello";
		// byte helloBytes[]=hello.getBytes();
		// myChunk.setBytes( helloBytes, 0, helloBytes.length);
		//
		//
		// res.doWrite(myChunk);
		// }
		protected C2BConverter getOut(final Response res) throws IOException {
			// You can fine tune the buffers. In a real app - this should be
			// reused, this is just
			// an example to show how the buffers are used.
			final ByteChunk myChunk = new ByteChunk(1024);
			myChunk.setLimit(4096);
			C2BConverter out = new C2BConverter(myChunk, "UTF8");

			// You can set limit to -1, add to it, and explicitly write when you
			// want to, or you can have it write automatically when the buffer
			// is filled.
			myChunk.setByteOutputChannel(new ByteChunk.ByteOutputChannel() {
				public void realWriteBytes(byte cbuf[], int off, int len)
						throws IOException {
					res.doWrite(myChunk);
				}
			});
			return out;
		}

		public void service(Request req, final Response res) throws Exception {
			System.out.println("Incoming request: uri=" + req.requestURI()
					+ " queryString=" + req.queryString().toString()
					+ " protocol=" + req.protocol().toString());

			res.setStatus(200);

			res.setHeader("foo", "bar");
			res.setContentType("text/plain");

			// We must explicitely flush the headers.
			res.sendHeaders();

			// tomcat doesn't use a stream internally - so the object can be
			// recycled and avoids
			// buffer to buffer copy.

			// To write to the stream, tomcat uses 'byte chunk' - a buffer
			// optimized for char-byte conversions
			// This is similar with NIO buffers
			C2BConverter out = getOut(res);

			// You can also add bytes
			// ByteChunk myChunk=out.getByteChunk();
			// String h="hellow";
			// byte hB[]=h.getBytes();
			// myChunk.append( hB, 0, hB.length);

			out.convert("Hello World");
			// make sure all the chars are sent to the byte[].
			// Unlike OutputStream/Writer - you can mix char and bytes, but you
			// must remember to flush when switching.
			out.flushBuffer();

			// Send it to the stream. Output will also be sent when the buffer
			// is full, based on the limit
			// Buffer size is set with myChunk.setLimit()
			out.getByteChunk().flushBuffer();

			// final processing
			res.finish();

			// Alternatively, you can use a growing ByteChunk and write it
			// explicitely:
			// res.doWrite(myChunk);
			req.recycle();
			res.recycle();
		}

		@Override
		public boolean event(Request req, Response res, SocketStatus status)
				throws Exception {
			System.out.println(status.name());
			return false;
		}

		@Override
		public boolean asyncDispatch(Request arg0, Response arg1,
				SocketStatus arg2) throws Exception {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public String getDomain() {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public void log(Request arg0, Response arg1, long arg2) {
			// TODO Auto-generated method stub
		}
	}

	public static void main(String args[]) throws Exception {
		StartHttp11Server.startHttp(80);
	}

}
